package com.xhwl.centiotdata.suppliersystem.eesd.qiming;

import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.xhwl.centiotdata.constant.EesdConstant;
import com.xhwl.centiotdata.utils.EncodeUtil;
import com.xhwl.centiotdata.utils.HMacMD5;
import com.xhwl.centiotdata.utils.RedisUtils;
import com.xhwl.common.dto.cent.iotdata.ev.ChargeConfigDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * @Description: 充电桩工具类
 * @Copyright: Copyright (c) 2021  ALL RIGHTS RESERVED.
 * @Company: 深圳市兴海物联科技有限公司
 * @Author: gyc
 * @CreateDate: 2021/12/8 17:21
 * @UpdateDate: 2021/12/8 17:21
 * @UpdateRemark: init
 * @Version: 1.0
 */
@Slf4j
@Component
public class QiMingUtil {

    @Resource
    private RedisUtils redisUtils;

    /**
     * 1、构造请求参数body
     *  示例：
     *  ChargeResultReqDTO parm = new ChargeResultReqDTO();
     *  parm.setStartChargeSeq("520");
     *  parm.setStartChargeSeqStat(1);
     *  parm.setConnectorID("520");
     *  parm.setStartTime("520");
     *  parm.setIdentCode("520");
     *  入参参数需要为json格式
     *  String jsonParam = JSONObject.toJSONString(parm);
     *  String buildReqParam = buildReqParam(jsonParam);
     * @param jsonParam json格式
     * @return 1、固定请求；2、返回加密参数Data和签名Sig
     */
    public String buildReqParam(String jsonParam, ChargeConfigDTO config) {
        JSONObject paramObj = new JSONObject();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String dateStr = sdf.format(new Date());
        paramObj.put("OperatorID", config.getOperatorId());
        paramObj.put("TimeStamp", dateStr);
        paramObj.put("Seq", HMacMD5.getSeq(dateStr));
        paramObj.put("Data", EncodeUtil.encrypt(jsonParam == null ? "{}" : jsonParam, config.getSecret(), config.getSecret()));
        // 签名要用operatorId+data+timestamp+seq生成
        String signMsg = paramObj.getString("OperatorID")
                + paramObj.getString("Data")
                + paramObj.getString("TimeStamp")
                + paramObj.getString("Seq");
        paramObj.put("Sig", HMacMD5.getHmacMd5Str(config.getSecret(), signMsg));
        return paramObj.toString();
    }

    /**
     * 2、获取token
     * @return  Authorization：Bearer 4e15a4cff5d2479c8a0601fdc09c90c1
     */
    public String getToken(ChargeConfigDTO config) {
        String token = (String) redisUtils.get(EesdConstant.QI_MING_TOKEN);
        if (StringUtils.isEmpty(token)) {
            // 正式环境
            String tokenUrl = config.getHost() + config.getTokenUrl();
            // 获取token请求参数
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("OperatorID", config.getOperatorId());
            jsonObject.put("OperatorSecret", config.getSecret());
            String jsonParam = JSONObject.toJSONString(jsonObject);
            String param = buildReqParam(jsonParam, config);
            String resp = HttpUtil.post(tokenUrl, param);
            JSONObject respObj = JSONObject.parseObject(resp);

            String ret = respObj.getString("Ret");
            String msg = respObj.getString("Msg");
            if (ret.equals(EesdConstant.SUCCESS_0_Str_CODE)) {
                String dataStr = respObj.getString("Data");
                String data = EncodeUtil.decrypt(dataStr, config.getSecret(), config.getSecret());
                JSONObject dataObj = JSONObject.parseObject(data);
                String succStat = dataObj.getString("SuccStat");
                if (succStat.equals(EesdConstant.SUCCESS_0_Str_CODE)) {
                    token = "Bearer " + dataObj.getString("AccessToken");
                    redisUtils.setWithMinute(EesdConstant.QI_MING_TOKEN, token, EesdConstant.HALF_AN_HOUR);
                }
            }
        }
        return token;
    }

    /**
     * 2、获取token
     * 推送的token
     * @return  Authorization：Bearer 4e15a4cff5d2479c8a0601fdc09c90c1
     */
    public JSONObject getAllToken(ChargeConfigDTO config) {
        JSONObject allToken = (JSONObject) redisUtils.get(EesdConstant.QI_MING_ALL_TOKEN);
        if (ObjectUtils.isEmpty(allToken)) {
            // 正式环境
            String tokenUrl = config.getHost() + config.getTokenUrl();
            // 获取token请求参数
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("OperatorID", config.getOperatorId());
            jsonObject.put("OperatorSecret", config.getSecret());
            String jsonParam = JSONObject.toJSONString(jsonObject);
            String param = buildReqParam(jsonParam, config);
            String resp = HttpUtil.post(tokenUrl, param);
            JSONObject respObj = JSONObject.parseObject(resp);

            String ret = respObj.getString("Ret");
            if (ret.equals(EesdConstant.SUCCESS_0_Str_CODE)) {
                String dataStr = respObj.getString("Data");
                String data = EncodeUtil.decrypt(dataStr, config.getSecret(), config.getSecret());
                allToken = JSONObject.parseObject(data);
                String succStat = allToken.getString("SuccStat");
                if (succStat.equals(EesdConstant.SUCCESS_0_Str_CODE)) {
                    String token = "Bearer " + allToken.getString("AccessToken");
                    redisUtils.setWithMinute(EesdConstant.QI_MING_TOKEN, token, EesdConstant.HALF_AN_HOUR);
                    redisUtils.setWithMinute(EesdConstant.QI_MING_ALL_TOKEN, allToken, EesdConstant.TEN_MINUTE);
                }
            }
        }
        return allToken;
    }

    /**
     * 3、解密结果
     * @param dataStr
     * @return
     */
    public String decryptData(String dataStr, ChargeConfigDTO config) {
        log.debug("充电桩解密：data:{}, dataSecret:{}, dataSecretiv:{}", dataStr, config.getSecret(), config.getSecret());
        return EncodeUtil.decrypt(dataStr, config.getSecret(), config.getSecret());
    }

    /**
     * 充电桩查询信息公共方法
     * @param obj map请求参数
     * @param url 请求url
     * @param key 缓存可以
     * @param validTime 缓存时间
     * @return 查询信息
     */
    public String queryInfo(JSONObject obj, String url, String key, Integer validTime, ChargeConfigDTO config) {
        log.info("请求:{}", obj.toJSONString());
        String param = buildReqParam(obj.toJSONString(), config);
        log.info("加密请求:{}", param);
        String resp = HttpRequest.post(url)
                .header(Header.AUTHORIZATION, getToken(config))
                .body(param)
                .execute().body();
        log.info("响应:{}", resp);
        JSONObject respObj = JSONObject.parseObject(resp);
        String ret = respObj.getString("Ret");
        String data;
        if (ret.equals(EesdConstant.SUCCESS_0_Str_CODE)) {
            String dataStr = respObj.getString("Data");
            data = EncodeUtil.decrypt(dataStr, config.getSecret(), config.getSecret());
            redisUtils.setWithMinute(key, data, validTime);
        } else {
            data = (String) redisUtils.get(key);
        }
        log.info("解密后data:{}", data);
        return data;
    }

    /**
     * 4、查询充电站信息
     * @param
     * @return
     */
    public String queryStationsInfo(ChargeConfigDTO config) {
        JSONObject obj = new JSONObject();
        obj.put("PageNo", config.getPageNo());
        obj.put("PageSize", config.getPageSize());
        String url = config.getHost() + config.getStationsUrl();
        String data = queryInfo(obj, url, EesdConstant.QI_MING_QUERY_STATIONS_INFO, EesdConstant.ONE_DAY, config);
        return data;
    }

    /**
     * 4、查询状态
     * StationlDs：这里注意，文档上是字符串，实际需要把字符串类型转换为数值类型
     * {"StationlDs":["653"]}
     * {"StationIDs":[653]}
     * @param
     * @return
     */
    public String queryStationsStatus(ChargeConfigDTO config) {
        JSONObject obj = new JSONObject();
        obj.put("StationIDs", Arrays.asList(config.getStationId()));
        String url = config.getHost() + config.getStatusUrl();
        String data = queryInfo(obj, url, EesdConstant.QI_MING_QUERY_STATIONS_STATUS, EesdConstant.HALF_AN_HOUR, config);
        return data;

    }

    /**
     * 4、查询统计信息
     * @param
     * @return
     */
    public String queryStationsStats(ChargeConfigDTO config, String startStr, String endStr) {
        JSONObject obj = new JSONObject();
        obj.put("StationID", config.getStationId());
        obj.put("StartTime", startStr);
        obj.put("EndTime", endStr);
        String url = config.getHost() + config.getStatsUrl();
        String data = queryInfo(obj, url, EesdConstant.QI_MING_QUERY_STATIONS_STATS, EesdConstant.HALF_AN_HOUR, config);
        return data;
    }

}
